﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Q.Framework.Data;
using System.Data.Objects;
using Q.Framework.Extension;
using System.Linq.Expressions;
using Q.Framework.WebControls;

namespace Q.Framework.Utility
{
    public interface ILookupSearch
    {
        Type BusinessType { get; set; }
        String KeyFieldName { get; set; }
        String DescriptionFieldName { get; set; }
        Boolean ShowDescription { get; set; }
        TypeExpression TypeOfKeyTextBox { get; set; }
        List<KeyValuePair<String, Object>> Filters { get; set; }

        String CrudUrl { get; set; }
        Dictionary<String, String> CrudParameters { get; set; }
        Boolean AllowFastCrud { get; set; }

        Object GetObjectById(Int32 ID);
        IPagedList GetPagedList(String descricao, Int32 pageIndex, Int32 pageSize);
        Object GetObjectByKeyField(String value);
    }

    [Serializable]
    public class LookupSearch<T> : ILookupSearch
    {
        public LookupSearch()
        {
            BusinessType = typeof(T);
            KeyFieldName = "ID";
            DescriptionFieldName = "Descricao";
            TypeOfKeyTextBox = TypeExpression.Inteiro;
            Filters = new List<KeyValuePair<string, object>>();
            CrudParameters = new Dictionary<string, string>();
        }

        public Type BusinessType { get; set; }
        public String KeyFieldName { get; set; }
        public String DescriptionFieldName { get; set; }
        public Boolean ShowDescription { get; set; }
        public Boolean AllowFastCrud { get; set; }
        public TypeExpression TypeOfKeyTextBox { get; set; }
        public List<KeyValuePair<String, Object>> Filters { get; set; }
        public String CrudUrl { get; set; }
        public Dictionary<String, String> CrudParameters { get; set; }

        public static LookupSearch<T> Create(Expression<Func<T, Object>> keyField = null, Expression<Func<T, String>> descriptionField = null, Q.Framework.WebControls.TypeExpression typeText = TypeExpression.Inteiro)
        {
            if (keyField != null && !(keyField.Body is MemberExpression))
                throw new ArgumentException("keyField parameter is invalid");

            LookupSearch<T> l = new LookupSearch<T>();
            if (keyField != null)
                l.KeyFieldName = (keyField.Body as MemberExpression).Member.Name;

            if (descriptionField != null)
            {
                l.ShowDescription = true;
                l.DescriptionFieldName = (descriptionField.Body as MemberExpression).Member.Name;
            }

            l.TypeOfKeyTextBox = typeText;

            return l;
        }

        public LookupSearch<T> KeyFieldDefinition(Expression<Func<T, Object>> keyField, TypeExpression typeText = TypeExpression.Inteiro)
        {
            if (keyField != null && !(keyField.Body is MemberExpression))
                throw new ArgumentException("keyField parameter is invalid");
            if (keyField != null)
                KeyFieldName = (keyField.Body as MemberExpression).Member.Name;
            TypeOfKeyTextBox = typeText;

            return this;
        }

        public LookupSearch<T> DescriptionFieldDefinition(Expression<Func<T, String>> descriptionField)
        {
            if (descriptionField != null)
            {
                ShowDescription = true;
                DescriptionFieldName = (descriptionField.Body as MemberExpression).Member.Name;
            }

            return this;
        }

        public LookupSearch<T> CrudDefinition(String url, Dictionary<String, String> parameters = null)
        {
            CrudUrl = url;
            AllowFastCrud = true;
            if (parameters != null)
                CrudParameters = parameters;
            return this;
        }
            
        public LookupSearch<T> AddFilter(Expression<Func<T, Object>> property, Object value)
        {
            if (property == null || !(property.Body is MemberExpression))
                throw new ArgumentException("property parameter is invalid");

            Filters.Add(new KeyValuePair<String, Object>(property.ToString(), value));

            return this;
        }

        public IPagedList GetPagedList(string description, int pageIndex, int pageSize)
        {
            var dao = new Q.Framework.Data.DAO<T>();
            String command = String.Format("SELECT VALUE {0} FROM {0} WHERE {0}.{1} Like '%' + @Description + '%'", dao.GetEntitySetName(), DescriptionFieldName);

            if (Filters != null && Filters.Any())
                for (int i = 0; i < Filters.Count; i++)
                    command += String.Format(" AND {0}.{1} = @pLookupQuery{2}", dao.GetEntitySetName(), Filters[0].Key, i.ToString().Trim());

            ObjectQuery<T> objQuery = new ObjectQuery<T>(command, ContextManager.Context);
            objQuery.Parameters.Add(new ObjectParameter("Description", description));

            if (Filters != null && Filters.Any())
                for (int i = 0; i < Filters.Count; i++)
                    objQuery.Parameters.Add(new ObjectParameter("pLookupQuery" + i.ToString().Trim(), Filters[0].Value));

            return new PagedList<T>(objQuery.OrderBy("it." + DescriptionFieldName), pageIndex, pageSize);
        }

        public Object GetObjectByKeyField(String value)
        {
            var dao = new Q.Framework.Data.DAO<T>();
            String command = String.Format("SELECT VALUE {0} FROM {0} WHERE {0}.{1} = @Key", dao.GetEntitySetName(), KeyFieldName);

            if (Filters != null && Filters.Any())
                for (int i = 0; i < Filters.Count; i++)
                    command += String.Format(" AND {0}.{1} = @pLookupQuery{2}", dao.GetEntitySetName(), Filters[0].Key, i.ToString().Trim());

            ObjectQuery<T> objQuery = new ObjectQuery<T>(command, ContextManager.Context);
            objQuery.Parameters.Add(new ObjectParameter("Key", value.ConvertTo(typeof(T).GetProperty(KeyFieldName).PropertyType)));

            if (Filters != null && Filters.Any())
                for (int i = 0; i < Filters.Count; i++)
                    objQuery.Parameters.Add(new ObjectParameter("pLookupQuery" + i.ToString().Trim(), Filters[0].Value));

            return objQuery.FirstOrDefault();
        }

        public Object GetObjectById(Int32 ID)
        {
            return Q.Framework.Data.DAOGeneric.GetById<T>(ID);
        }
    }
}